package com.blue.encryption;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;

import java.security.*;

/**
 * @Description: Signature数字签名
 *      双密钥摘要技术
 *      Signature的使用说明四个步骤
 *      // 1.创建数字签名对象
 *      Signature.getInstance(algorithm);
 *      //2.初始化密钥（初始化密钥或公钥）
 *      signature.initSign(privateKey);初始化签署签名的私钥
 *      signature.initVerify(publicKey);初始化验证签名的公钥
 *      //3更新要签名或这验证的字节
 *      signature.update(data);
 *      //4.签署或验证所有更新字节的签名
 *      signature.sign() 返回签署后的byte[]
 *      signature.verify(byte[]) 验证传入的签名内容返回boolean
 *
 *    参考资料https://blog.csdn.net/mn960mn/article/details/78177250
 *    Signature.getInstance(algorithm) 算法格式为 <digest>with<encryption>
 * 	 支持的算法有：MD5withRSA、SHA256withRSA、SHA256withDSA等等
 * 	 全部支持的算法见官方文档：
 * 	 https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Signature
 * @Auther: lbb
 * @Date: 2019/1/23 10:43
 */
public class SignatureUtil {
    public static final String ALGORITHM_NAME="RSA";
    public static final String SIGNATRUE_ALGORITHM_MD5_WITH_RSA="MD5withRSA";
    public static final String SIGNATRUE_ALGORITHM_SHA256_WITH_RSA="SHA256withRSA";
    public static final String SIGNATRUE_ALGORITHM_SHA256_WITH_DSA="SHA256withDSA";

    /**
     * 生成密钥对
     * @return
     * @throws Exception
     */
    public static KeyPair generateKeyPair(){

        //1.根据现有的公钥私钥文件生成KeyPair
//        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME);
//        byte[] publicKeyData = Files.readAllBytes(Paths.get("c:/tmp/pubkey.der"));
//        byte[] privateKeyData = Files.readAllBytes(Paths.get("c:/tmp/pkcs8_prikey.der"));
//        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyData);
//        PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyData);
//        PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
//        PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
//        return new KeyPair(publicKey, privateKey);
        //2.由KeyPairGenerator（密钥对生成器）获取密钥对
        KeyPairGenerator keyPairGenerator= null;
        try {
            keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM_NAME);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        //获取密钥对
        KeyPair keyPair=keyPairGenerator.generateKeyPair();
        return keyPair;
    }

    /**
     *  私钥签名
     * @param algorithm 算法
     * @param privateKey 私钥
     * @param content 内容
     * @return
     */
    private static String sign(String algorithm,PrivateKey privateKey,byte[] content){
        String signHexStr="";
        try {
            //1.创建数字签名
            Signature signature=Signature.getInstance(algorithm);
            //2.初始化私钥
            signature.initSign(privateKey);
            //3.使用指定的数组更新要签名的数据
            signature.update(content);
            //4.签名操作的签名结果
            byte[] sign=signature.sign();
            signHexStr= Hex.encodeHexString(sign);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return signHexStr;
    }
    /**
     *  公钥验证
     * @param algorithm 算法
     * @param publicKey 公钥
     * @param content 内容
     * @param signHexStr 摘要
     * @return
     */
    private static boolean verify(String algorithm,PublicKey publicKey,byte[] content,String signHexStr){
       boolean verify=false;
        try {
            //1.创建数字签名
            Signature signature=Signature.getInstance(algorithm);
            //2.初始化公钥
            signature.initVerify(publicKey);
            //3.使用指定的数组更新要签名的数据
            signature.update(content);
            //4.验证签名的结果
            byte[] sign= Hex.decodeHex(signHexStr.toCharArray());
            verify =signature.verify(sign);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (DecoderException e) {
            e.printStackTrace();
        }
        return verify;
    }

}
